import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.*;

public class homework_07 extends Application {

    private static class Edge {
        int yMax;
        float x;
        float slope;

        Edge(int yMax, float x, float slope) {
            this.yMax = yMax;
            this.x = x;
            this.slope = slope;
        }
    }

    @Override
    public void start(Stage primaryStage) {
        Canvas canvas = new Canvas(400, 400); // 增大画布大小
        GraphicsContext gc = canvas.getGraphicsContext2D();

        // 定义三个太阳的顶点和颜色
        List<Point> sun1Points = createSun(100, 100, 30, 12); // 太阳1
        List<Point> sun2Points = createSun(300, 150, 40, 16); // 太阳2
        List<Point> sun3Points = createSun(200, 300, 50, 20); // 太阳3

        // 填充太阳1（橙色）
        gc.setFill(Color.ORANGE);
        scanlineFill(gc, sun1Points);

        // 填充太阳2（黄色）
        gc.setFill(Color.YELLOW);
        scanlineFill(gc, sun2Points);

        // 填充太阳3（红色）
        gc.setFill(Color.RED);
        scanlineFill(gc, sun3Points);

        // 绘制太阳边框
        gc.setStroke(Color.BLACK);
        gc.setLineWidth(1); // 设置边界线宽度
        drawSun(gc, sun1Points);
        drawSun(gc, sun2Points);
        drawSun(gc, sun3Points);

        StackPane root = new StackPane(canvas);
        primaryStage.setScene(new Scene(root));
        primaryStage.setTitle("Scanline Fill Algorithm - Multi Sun");
        primaryStage.show();
    }

    /**
     * 创建太阳的顶点
     *
     * @param centerX 中心点x坐标
     * @param centerY 中心点y坐标
     * @param radius 半径
     * @param rays 光线数量
     * @return 太阳的顶点列表
     */
    private List<Point> createSun(int centerX, int centerY, int radius, int rays) {
        List<Point> sunPoints = new ArrayList<>();
        double angleIncrement = 2 * Math.PI / rays; // 每条光线之间的角度

        for (int i = 0; i < rays; i++) {
            double angle = i * angleIncrement;

            // 光线外点
            double outerX = centerX + 1.5 * radius * Math.cos(angle);
            double outerY = centerY - 1.5 * radius * Math.sin(angle); // y轴向下为正方向
            sunPoints.add(new Point((int) outerX, (int) outerY));

            // 光线内点（圆形边缘）
            double innerX = centerX + radius * Math.cos(angle + angleIncrement / 2);
            double innerY = centerY - radius * Math.sin(angle + angleIncrement / 2);
            sunPoints.add(new Point((int) innerX, (int) innerY));
        }

        return sunPoints;
    }

    /**
     * 绘制太阳边框
     */
    private void drawSun(GraphicsContext gc, List<Point> sunPoints) {
        for (int i = 0; i < sunPoints.size(); i++) {
            Point p1 = sunPoints.get(i);
            Point p2 = sunPoints.get((i + 1) % sunPoints.size());
            gc.strokeLine(p1.x, p1.y, p2.x, p2.y);
        }
    }

    /**
     * 扫描线填充算法
     */
    private void scanlineFill(GraphicsContext gc, List<Point> polygon) {
        Map<Integer, List<Edge>> edgeTable = new HashMap<>();

        // 构建边表
        for (int i = 0; i < polygon.size(); i++) {
            Point p1 = polygon.get(i);
            Point p2 = polygon.get((i + 1) % polygon.size());

            // 跳过水平边
            if (p1.y == p2.y) continue;

            // 确定边的方向
            boolean upward = p1.y > p2.y; // y轴向下为正方向
            int yMin = upward ? p2.y : p1.y;
            int yMax = upward ? p1.y : p2.y;
            float x = upward ? p2.x : p1.x;
            float slope = (p2.x - p1.x) / (float) (p2.y - p1.y);

            edgeTable.computeIfAbsent(yMin, k -> new ArrayList<>())
                    .add(new Edge(yMax, x, slope));
        }

        // 初始化活动边表
        List<Edge> activeEdges = new ArrayList<>();
        int yStart = Collections.min(edgeTable.keySet());
        int yEnd = polygon.stream().mapToInt(p -> p.y).max().orElse(yStart);

        for (int y = yStart; y < yEnd; y++) {
            // 添加新边
            if (edgeTable.containsKey(y)) {
                activeEdges.addAll(edgeTable.get(y));
            }

            // 移除已完成的边
            int finalY = y;
            activeEdges.removeIf(edge -> finalY >= edge.yMax);

            // 按x坐标排序
            activeEdges.sort(Comparator.comparingDouble(e -> e.x));

            // 填充扫描线
            for (int i = 0; i < activeEdges.size(); i += 2) {
                Edge left = activeEdges.get(i);
                Edge right = activeEdges.get(i + 1);
                int xStart = (int) Math.ceil(left.x);
                int xEnd = (int) Math.floor(right.x);
                if (xEnd > xStart) {
                    gc.fillRect(xStart, y, xEnd - xStart, 1);
                }
            }

            // 更新x坐标
            for (Edge edge : activeEdges) {
                edge.x += edge.slope;
            }
        }
    }

    private static class Point {
        int x;
        int y;

        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}